/**
 * 	XMLReader.java
 *
 *  This file is part of the PDFGen Syllabus Formatter Project.
 *  Copyright (C) 2011  Gian Fontanilla
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.dlsu.pdfgen.io;

import java.io.File;

import javax.swing.JOptionPane;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.dlsu.pdfgen.exceptions.InvalidXMLFileFormatException;
import org.dlsu.pdfgen.gui.ErrorFrame;
import org.dlsu.pdfgen.struct.Syllabus;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * Reads a properly formatted XML file. A singleton implementation - thus cannot
 * be instantiated. Use the static method <CODE>getInstance()</CODE> instead.
 * 
 * @author Gian Fontanilla
 * @version 0.03a
 * @see Syllabus
 */
public class XMLReader {

	private DocumentBuilderFactory dbf;
	private DocumentBuilder db;
	private Document doc;
	private Syllabus s;
	
	/**
	 * Private constructor. Necessary to prevent this class from being
	 * instantiated elsewhere.
	 */
	protected XMLReader() {
	}

	/**
	 * The private static singleton holder class.
	 * 
	 * @author Gian Fontanilla
	 */
	private static class SingletonXMLReader {

		/** The singleton instance attribute */
		public static final XMLReader INSTANCE = new XMLReader();
	}

	/**
	 * Returns the singleton instance of the singleton.
	 * 
	 * @return The singleton instance of this class
	 */
	public static XMLReader getInstance() {
		return SingletonXMLReader.INSTANCE;
	}

	/**
	 * Reads an XML file containing syllabus information and creates a
	 * <CODE>Syllabus</CODE> object based on what was read.
	 * 
	 * @param fileName
	 *            The input XML file
	 * @return The resulting <CODE>Syllabus</CODE> object
	 * @throws InvalidXMLFileFormatException 
	 */
	
	public NodeList getSyllabusTag(NodeList nodeLst) throws InvalidXMLFileFormatException{
		nodeLst = doc.getElementsByTagName("syllabus");
		if (nodeLst == null)
			throw new InvalidXMLFileFormatException();
		
		return nodeLst;
	}
	
	public NodeList getCodeTag(NodeList nodeLst){
		nodeLst = doc.getElementsByTagName("code");
		System.out.println("BALHSADASKJHDSAKJHDKSAHJSAHKSHDAHA " + s.getCourseCode());
		
		return nodeLst;
	}
	
	public NodeList getTitleTag(NodeList nodeLst){
		nodeLst = doc.getElementsByTagName("title");
		return nodeLst;
	}
	
	public NodeList getTypeTag(NodeList nodeLst){
		nodeLst = doc.getElementsByTagName("type");
		return nodeLst;
	}
	
	public NodeList getFacultyTag(NodeList nodeLst){
		nodeLst = doc.getElementsByTagName("faculty");
		return nodeLst;
	}
	
	public NodeList getCourseDescTag(NodeList nodeLst){
		nodeLst = doc.getElementsByTagName("coursedesc");
		return nodeLst;
	}
	
	public NodeList getTermTag(NodeList nodeLst){
		nodeLst = doc.getElementsByTagName("term");
		return nodeLst;
	}
	
	public NodeList getTimeTag(NodeList nodeLst){
		nodeLst = doc.getElementsByTagName("time");
		return nodeLst;
	}
	
	public NodeList getRoomTag(NodeList nodeLst){
		nodeLst = doc.getElementsByTagName("room");
		return nodeLst;
	}
	
	public NodeList getPreReqsTag(NodeList nodeLst){
		nodeLst = doc.getElementsByTagName("prereqs");
		{
			NodeList prereqs = nodeLst.item(0).getChildNodes();

			for (int i = 0; i < prereqs.getLength(); i++) {
				Node node = prereqs.item(i);
				if (node.getTextContent().trim().length() > 0)
					s.getPreRequisiteCourses().add(node.getTextContent());
			}
		}
		return nodeLst;
	}
	
	public NodeList getPostReqsTag(NodeList nodeLst){
		nodeLst = doc.getElementsByTagName("postreqs");
		{
			NodeList postreqs = nodeLst.item(0).getChildNodes();

			for (int i = 0; i < postreqs.getLength(); i++) {
				Node node = postreqs.item(i);
				if (node.getTextContent().trim().length() > 0)
					s.getPostRequisiteCourses().add(node.getTextContent());
			}
		}
		return nodeLst;
	}
	
	public NodeList getObjectivesTag(NodeList nodeLst){
		nodeLst = doc.getElementsByTagName("objectives");
		{
			Element node = (Element) nodeLst.item(0);
			s.setObjectivePreamble(node.getElementsByTagName("preamble")
					.item(0).getTextContent());

			NodeList objectives = node.getElementsByTagName("objective");
			for (int i = 0; i < objectives.getLength(); i++) {
				s.getObjectives().add(objectives.item(i).getTextContent());
			}
		}
		return nodeLst;
	}
	
	public NodeList getRequirementsTag(NodeList nodeLst){
		nodeLst = doc.getElementsByTagName("requirements");
		{
			NodeList requirements = nodeLst.item(0).getChildNodes();
			s.setRequirementListType(((Element) nodeLst.item(0))
					.getAttribute("listType"));

			for (int i = 0; i < requirements.getLength(); i++) {
				Node node = requirements.item(i);
				if (node.getTextContent().trim().length() > 0)
					s.getRequirements().add(node.getTextContent());
			}
		}
		
		return nodeLst;
	}
	
	public NodeList getMaterialsTag(NodeList nodeLst){
		nodeLst = doc.getElementsByTagName("materials");
		{
			NodeList materials = nodeLst.item(0).getChildNodes();
			s.setMaterialListType(((Element) nodeLst.item(0))
					.getAttribute("listType"));

			for (int i = 0; i < materials.getLength(); i++) {
				Node node = materials.item(i);
				if (node.getTextContent().trim().length() > 0)
					s.getMaterials().add(node.getTextContent());
			}
		}
		
		return nodeLst;
	}
	
	public NodeList getReferencesTag(NodeList nodeLst){
		nodeLst = doc.getElementsByTagName("references");
		{
			NodeList references = nodeLst.item(0).getChildNodes();
			s.setReferenceListType(((Element) nodeLst.item(0))
					.getAttribute("listType"));

			for (int i = 0; i < references.getLength(); i++) {
				Node node = references.item(i);
				if (node.getTextContent().trim().length() > 0)
					s.getReferences().add(node.getTextContent());
			}
		}
		
		return nodeLst;
	}
	
	public NodeList getAssessmentTag(NodeList nodeLst){
		nodeLst = doc.getElementsByTagName("assessments");
		{
			NodeList assessments = nodeLst.item(0).getChildNodes();

			for (int i = 0; i < assessments.getLength(); i++) {

				if (assessments.item(i) instanceof Element) {

					Element nodeElement = (Element) assessments.item(i);
					s.getAssessments().add(
							s.createAssessment(nodeElement
									.getElementsByTagName("item").item(0)
									.getTextContent(), nodeElement
									.getElementsByTagName("value").item(0)
									.getTextContent()));
				}

			}
		}
		return nodeLst;
	}
	
	public NodeList getTopicsTag(NodeList nodeLst){
		nodeLst = doc.getElementsByTagName("topics");
		{
			NodeList topics = nodeLst.item(0).getChildNodes();

			for (int i = 0; i < topics.getLength(); i++) {

				if (topics.item(i) instanceof Element) {

					Element nodeElement = (Element) topics.item(i);
					s.getTopics().add(
							s.createTopic(
									nodeElement
											.getElementsByTagName("name")
											.item(0).getTextContent(),
									nodeElement
											.getElementsByTagName("week")
											.item(0).getTextContent(),
									nodeElement
											.getElementsByTagName("hour")
											.item(0).getTextContent()

							));
				}

			}
		}
		return nodeLst;
	}
	
	public Syllabus readSyllabus(String fileName)
			throws InvalidXMLFileFormatException {

		// Syllabus object to be returned later
		s = new Syllabus();

		try {
			File file = new File(fileName);
			System.out.println(file.getName());
			dbf = DocumentBuilderFactory.newInstance();
			db = dbf.newDocumentBuilder();
			doc = db.parse(file);
			doc.getDocumentElement().normalize();
			NodeList nodeLst = null;
			
			nodeLst = getSyllabusTag(nodeLst);
			nodeLst = getCodeTag(nodeLst);
			s.setCourseCode(nodeLst.item(0).getTextContent());
			nodeLst = getTitleTag(nodeLst);
			s.setCourseTitle(nodeLst.item(0).getTextContent());
			nodeLst = getTypeTag(nodeLst);
			s.setCourseType(nodeLst.item(0).getTextContent());
			nodeLst = getFacultyTag(nodeLst);
			s.setFaculty(nodeLst.item(0).getTextContent());
			nodeLst = getCourseDescTag(nodeLst);
			s.setCourseDesc(nodeLst.item(0).getTextContent());
			nodeLst = getTermTag(nodeLst);
			s.setTerm(nodeLst.item(0).getTextContent());
			nodeLst = getTimeTag(nodeLst);
			s.setTime(nodeLst.item(0).getTextContent());
			nodeLst = getRoomTag(nodeLst);
			s.setRoom(nodeLst.item(0).getTextContent());
			nodeLst = getPreReqsTag(nodeLst);
			nodeLst = getPostReqsTag(nodeLst);
			nodeLst = getObjectivesTag(nodeLst);
			nodeLst = getMaterialsTag(nodeLst);
			nodeLst = getReferencesTag(nodeLst);
			nodeLst = getAssessmentTag(nodeLst);
			nodeLst = getTopicsTag(nodeLst);
		} catch (NullPointerException e) {
			e.printStackTrace();
			new ErrorFrame(e.getLocalizedMessage()).show();
			throw new InvalidXMLFileFormatException();
		} catch (org.xml.sax.SAXParseException e) {
			e.printStackTrace();
			new ErrorFrame("Error on file : " + e.getSystemId() + "\n\n"
					+ e.getLocalizedMessage()).show();
			throw new InvalidXMLFileFormatException();
		} catch (Exception e) {
			e.printStackTrace();

		}
		return s;
	}
	
	
}
